package com.wanji.gateway.device;

import com.wanji.gateway.command.DeviceCommand;
import com.wanji.gateway.constant.CommonConstant;
import com.wanji.gateway.constant.DeviceStatus;
import com.wanji.gateway.event.DeviceMessageEvent;
import com.wanji.gateway.model.DeviceContext;
import com.wanji.protocol.api.DeviceMessage;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelId;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;


@Slf4j
@Service
@RequiredArgsConstructor
public class DeviceManager {

    private final CommandScheduler commandScheduler;
    private final ApplicationEventPublisher eventPublisher;
    private static final ConcurrentMap<String, DeviceContext> DEVICES = new ConcurrentHashMap<>();

    /**
     * ChannelID -> 设备ID映射（用于连接断开时查找设备ID）
     */
    private static final Map<ChannelId, String> channelIdToDeviceId = new ConcurrentHashMap<>();

    public void registerDevice(String deviceId, String ip, Channel channel) {
        // 创建设备上下文并注册
        // 创建设备上下文（若不存在则新建，存在则更新）
        DeviceContext context = DEVICES.computeIfAbsent(deviceId, id ->
                new DeviceContext(
                        deviceId,
                        ip,
                        channel,
                        LocalDateTime.now(),
                        LocalDateTime.now(),
                        true)
        );
        // 更新Channel和心跳时间
        context.updateChannel(channel);
        context.updateHeartbeatTime(LocalDateTime.now());


        // 记录Channel与设备ID的映射
        channel.attr(CommonConstant.DEVICE_ID).set(deviceId);
        channelIdToDeviceId.put(channel.id(), deviceId);

        log.info("设备[{}]已注册（从消息获取ID）", deviceId);
        // commandScheduler.scheduleInitialization(deviceId);
    }

    public void publishEvent(DeviceMessage message, String deviceId) {
        // 创建设备消息事件并发布
        DeviceMessageEvent event = new DeviceMessageEvent(this, message, deviceId);
        eventPublisher.publishEvent(event);
    }

    public void sendCommand(String deviceId, DeviceCommand command) {
        DeviceContext context = DEVICES.get(deviceId);
        if (context != null && context.isActive()) {
            Channel channel = context.getChannel();
            if (channel == null || !channel.isActive()) {
                log.warn("设备[{}]已离线，无法发送命令", deviceId);
                return;
            }
            byte[] data = command.encode();
            ChannelFuture future = channel.writeAndFlush(Unpooled.copiedBuffer(data));
            future.addListener((ChannelFutureListener) f -> {
                if (!f.isSuccess()) {
                    log.error("设备[{}]发送命令失败", deviceId, f.cause());
                }
            });
            // commandScheduler.submitCommand(deviceId, command);
        } else {
            throw new RuntimeException("设备离线: " + deviceId);
        }
    }

    /**
     * 注销设备
     *
     * @param deviceId 设备ID
     */
    public static void unregisterDevice(String deviceId) {
        DeviceContext context = DEVICES.remove(deviceId);
        if (context != null) {
            context.close();
            channelIdToDeviceId.values().remove(deviceId);
            log.info("设备[{}]已注销", deviceId);
        }
    }

    /**
     * 根据ChannelID获取设备ID
     *
     * @param channelId ChannelID
     * @return 设备ID（若存在）
     */
    public String getDeviceIdByChannel(ChannelId channelId) {
        return channelIdToDeviceId.get(channelId);
    }

    /**
     * 根据设备ID获取Channel
     *
     * @param deviceId 设备ID
     * @return 设备连接Channel
     */
    public static Channel getChannel(String deviceId) {
        DeviceContext context = DEVICES.get(deviceId);
        return context != null ? context.getChannel() : null;
    }

    /**
     * 根据设备ID获取设备状态
     *
     * @param deviceId 设备ID
     * @return 设备状态
     */
    public DeviceStatus getStatus(String deviceId) {
        DeviceContext context = DEVICES.get(deviceId);
        return context != null ? context.getStatus() : DeviceStatus.OFFLINE;
    }

    /**
     * 获取所有设备状态
     */
    public Map<String, DeviceStatus> getAllStatus() {
        return DEVICES.entrySet().stream()
                .collect(Collectors.toMap(
                        Map.Entry::getKey,
                        e -> e.getValue().getStatus()
                ));
    }
}
